@file:JvmName("PluginUtils")

package com.jetbrains.edu.learning

import com.intellij.externalDependencies.DependencyOnPlugin
import com.intellij.externalDependencies.ExternalDependenciesManager
import com.intellij.ide.plugins.PluginEnabler
import com.intellij.ide.plugins.PluginManagerCore
import com.intellij.openapi.application.ApplicationManager
import com.intellij.openapi.application.ApplicationNamesInfo
import com.intellij.openapi.application.ex.ApplicationManagerEx
import com.intellij.openapi.diagnostic.Logger
import com.intellij.openapi.extensions.PluginId
import com.intellij.openapi.project.Project
import com.intellij.openapi.ui.Messages
import com.intellij.openapi.updateSettings.impl.pluginsAdvertisement.installAndEnable
import com.jetbrains.edu.learning.courseFormat.Course
import com.jetbrains.edu.learning.courseFormat.ext.compatibilityProvider
import com.jetbrains.edu.learning.messages.EduCoreBundle

fun getDisabledPlugins(ids: List<PluginId>): List<PluginId> {
  return ids.filter { PluginManagerCore.isDisabled(it) }
}

private fun restartIDE(messageInfo: String) {
  val ideName = ApplicationNamesInfo.getInstance().fullProductName
  val restartInfo = if (ApplicationManager.getApplication().isRestartCapable) {
    EduCoreBundle.message("ide.restart.info.title", ideName)
  }
  else {
    EduCoreBundle.message("ide.restart.message.title", ideName)
  }

  val message = if (ApplicationManager.getApplication().isRestartCapable) {
    "$messageInfo. ${EduCoreBundle.message("ide.restart.info.message", ideName)}"
  }
  else {
    "$messageInfo. ${EduCoreBundle.message("ide.restart.message", ideName)}"
  }

  Messages.showInfoMessage(message, restartInfo)
  ApplicationManagerEx.getApplicationEx().restart(true)
}

fun pluginVersion(pluginId: String): String? = PluginManagerCore.getPlugin(PluginId.getId(pluginId))?.version

fun setUpPluginDependencies(project: Project, course: Course) {
  val allDependencies = course.pluginDependencies.map { DependencyOnPlugin(it.stringId, it.minVersion, it.maxVersion) }.toMutableList()

  course.compatibilityProvider?.requiredPlugins()?.forEach { plugin ->
    if (allDependencies.none { plugin.stringId == it.pluginId }) {
      allDependencies.add(DependencyOnPlugin(plugin.stringId, null, null))
    }
  }

  ExternalDependenciesManager.getInstance(project).setAllDependencies(allDependencies)
}

fun installAndEnablePlugin(pluginIds: Set<PluginId>, onSuccess: Runnable) = installAndEnable(null, pluginIds, true, onSuccess = onSuccess)

fun enablePlugins(pluginsId: List<PluginId>) {
  val descriptors = pluginsId.mapNotNull { pluginId -> PluginManagerCore.getPlugin(pluginId) }
  @Suppress("UnstableApiUsage")
  PluginEnabler.HEADLESS.enable(descriptors)
  restartIDE(EduCoreBundle.message("required.plugin.were.enabled"))
}

val TIME_LOGGER = Logger.getInstance("JetBrainsAcademy.performance.measure")

fun <T> measureTimeAndLog(
  title: String,
  logResult: Boolean = false,
  resultTransformer: (T) -> String? = { it?.toString() },
  block: () -> T
): T {
  val start = System.currentTimeMillis()

  try {
    val value = block()
    val time = System.currentTimeMillis() - start
    val message = "$title: $time ms" + if (logResult) " result: ${resultTransformer(value)}" else ""
    TIME_LOGGER.info(message)
    return value
  }
  catch (e: Throwable) {
    val time = System.currentTimeMillis() - start
    val message = "$title: $time ms finished with exception: ${e.javaClass} ${e.message}"
    TIME_LOGGER.info(message)
    throw e
  }
}